﻿using StackExchange.Redis;
using TeachlyQBank.DbPool;
using TeachlyQBank.Models;
using NLog;
using System.Data;
using System.Text.Json;
using Microsoft.IdentityModel.Tokens;

namespace TeachlyQBank.DbServer
{
    public class UserServer
    {
        private readonly IHttpContextAccessor _httpContextAccessor;
        private readonly MySqlConnectionAdapter _mysql; // 操作mysql的类
        private readonly IConnectionMultiplexer _redis;  // 操作redis的类
        private readonly Logger _logger;  //记录日志的类

        // 完成依赖注入
        public UserServer(MySqlConnectionAdapter mysql, IConnectionMultiplexer redis, IHttpContextAccessor httpContextAccessor)
        {
            _httpContextAccessor = httpContextAccessor;
            _redis = redis;
            _logger = LogManager.GetCurrentClassLogger();
            _mysql = mysql;
        }

        public int DeleteUserRole(string role_id, string permission_id)
        {
            _mysql.Open();
            string query = "DELETE FROM T_ROLE_PERMISSION  WHERE role_id=@role_id and permission_id=@permission_id";
            Dictionary<string, object> parameters = new Dictionary<string, object>
            {
                {"@role_id",role_id },
                {"@permission_id", permission_id},
            };
            int count = _mysql.ExecuteNonQuery(query, parameters);
            if (count > 0)
            {
                _mysql.Close();
                return count;
            }
            else
            {
                _mysql.Close();
                return -1;
            }
        }

        // 添加一个用户角色关联
        public int AddUserRole(RolePower rolePower)
        {
            _mysql.Open();
            string query = "INSERT INTO T_ROLE_PERMISSION (ro_pe_id,role_id,permission_id) values(@id,@role_id,@permission_Id)";
            Dictionary<string, object> parameters = new Dictionary<string, object>
            {
                {"@id",Guid.NewGuid().ToString() },
                {"@role_id", rolePower.role_id},
                {"@permission_id", rolePower.permission_id},
            };
            int count = _mysql.ExecuteNonQuery(query, parameters);
            if (count > 0)
            {
                _mysql.Close();
                return count;
            }
            else
            {
                _mysql.Close();
                return -1;
            }
        }

        // 查询所有权限的信息
        public List<Permission> GetAllPermissions()
        {
            _mysql.Open();

            string query = "SELECT * FROM T_PERMISSION";

            DataSet data = _mysql.ExecuteQuery(query);
            if (data == null || data.Tables[0].Rows.Count == 0)
            {
                _mysql.Close();
                // 查询出先错误
                _logger.Error($"查询出错,错误的sql语句:{_mysql.GetLastExecutedSql()},错误的信息:{_mysql.GetLastError()}");
                return null;
            }
            else
            {
                List<Permission> res = new List<Permission>();

                foreach (DataRow row in data.Tables[0].Rows)
                {
                    Permission node = new Permission();
                    node.permission_id = row["permission_id"].ToString();
                    node.permission_name = row["permission_name"].ToString();
                    node.description = row["description"].ToString();
                    node.resource = row["resource"].ToString();
                    node.action = row["action"].ToString();
                    node.domain = row["domain"].ToString() ;
                    res.Add(node);
                }
                _mysql.Close();

                return res;
            }

        }
        // 查询出所有关联的用户的信息和角色
        public List<RolePower> GetAllRolePower()
        {

            _mysql.Open();

            string query = "SELECT \r\n    r.roleid AS role_id,\r\n    r.rolename AS role_name,\r\n    p.permission_id AS " +
                "permission_id,\r\n    p.permission_name AS permission_name\r\nFROM T_ROLE r\r\nINNER JOIN " +
                "T_ROLE_PERMISSION rp ON r.roleid = rp.role_id\r\nINNER JOIN T_PERMISSION p ON p.permission_id = rp.permission_id;";

            DataSet data = _mysql.ExecuteQuery(query);
            if (data == null || data.Tables[0].Rows.Count == 0)
            {
                _mysql.Close();
                // 查询出先错误
                _logger.Error($"查询出错,错误的sql语句:{_mysql.GetLastExecutedSql()},错误的信息:{_mysql.GetLastError()}");
                return null;
            }
            else
            {
                List<RolePower> res = new List<RolePower>();

                foreach (DataRow row in data.Tables[0].Rows)
                {
                    RolePower node = new RolePower();

                    node.permission_id = row["permission_id"].ToString();
                    node.permission_name = row["permission_name"].ToString();
                    node.role_id = row["role_id"].ToString();
                    node.role_name = row["role_name"].ToString();

                    res.Add(node);
                }
                _mysql.Close();

                return res;
            }
        }

        // 功能:向数据库提交注册新用户的请求
        // 参数:输入一个User类型的数据做为要注册的用户
        // 返回:执行成功返回数据库影响数据的条数1,失败返回-1
        public int EnrollServer(User user)
        {
            _mysql.Open();

            //对密码进行加密
            string hashedPassword = BCrypt.Net.BCrypt.HashPassword(user.user_password);

            string query = "insert into T_USER(user_id,user_name,user_account,phone,user_password,role_id) " +
                "values(@user_id,@user_name,@user_account,@phone,@user_password,@role_id)";

            Dictionary<string, object> parameters = new Dictionary<string, object>
            {
                { "@user_id", Guid.NewGuid() },
                { "@user_name", user.user_name ! },
                { "@user_account", user.user_account !},
                { "@phone", user.phone !},
                { "@user_password",hashedPassword !}, 
                { "@role_id", 1},
            };
            
            int count=_mysql.ExecuteNonQuery(query,parameters);

            if ( count > 0 )
            {
                _logger.Info($"注册了一个新用户:{user.user_name},邮箱地址:{user.user_account},本次花费了{_mysql.GetLastExecutionTime()}毫秒");
                _mysql.Close();
                return count;
            }
            else 
            {
                _logger.Error($"创建用户出现错误,错误的sql语句:{_mysql.GetLastExecutedSql()},错误的信息:{_mysql.GetLastError()}");
                _mysql.Close();
                return -1;
            }
        }

        // 功能:向数据库提交登录的验证请求
        // 参数:一个User类型的数据保护了输入的邮箱和密码
        // 返回:如果找到了这个用户返回true,如果失败返回false
        public bool LoginServer(User user)
        {
            _mysql.Open();

            string query = "SELECT * FROM T_USER WHERE user_account = @user_account";
            Dictionary<string, object> parameters = new Dictionary<string, object>
            {
                { "@user_account", user.user_account !}
             };

            DataSet result = _mysql.ExecuteQuery(query, parameters);

             // 未找到这个用户
            if (result == null || result.Tables[0].Rows.Count == 0)
            {
                _mysql.Close();
                _logger.Error($"查询出错，错误信息：{_mysql.GetLastError()}");
                return false;
            }

            DataRow row = result.Tables[0].Rows[0];
            string storedHashPassword = row["user_password"].ToString() !;

            // 使用BCrypt进行密码验证
            try
            {
                if (BCrypt.Net.BCrypt.Verify(user.user_password, storedHashPassword))
                {
                    // 验证成功将用户的信息存储到cookie中
                    user.user_id = Guid.Parse( row["user_id"].ToString());
                    user.user_name = row["user_name"].ToString();
                    user.role_id = row["role_id"].ToString();
                    user.phone = row["phone"].ToString();
                    if (row["avater"] != DBNull.Value)
                    {
                        user.avater = (byte[])row["avater"];
                    }
                    else
                    {
                        // 读取默认头像的字节数据作为默认值
                        user.avater = System.IO.File.ReadAllBytes("wwwroot/img/pix1.jpg");
                    }
                    _mysql.Close();
                    StoreUserInfoInRedis(user);
                    return true;
                }
                else
                {
                    return false;
                }
            }
            catch
            {
                    _mysql.Close();
                    return false;
             }


        }
        /// <summary>
        //功能：用于修改用户信息
        //参数：传入一个user里面包含了修改用户的账号
        //返回:执行成分返回数据库影响的条数1,失败返回-1
        public int UpdServer(User user)
        {
            _mysql.Open();
            //对密码进行加密
            string hashedPassword = BCrypt.Net.BCrypt.HashPassword(user.user_password);
            string query = "UPDATE T_USER SET user_name=@user_name,user_account=@user_account,user_password=@user_password,phone=@phone,role_id=@role_id WHERE user_account=@user_account;";
            Dictionary<string, object> parameters = new Dictionary<string, object>
            {
                { "@user_name", user.user_name ! },
                { "@user_account", user.user_account !},
                { "@phone", user.phone !},
                { "@user_password",hashedPassword !},
                { "@role_id", 1},
            };
            int count = _mysql.ExecuteNonQuery(query, parameters);

            if (count > 0)
            {
                _logger.Info($"对:{user.user_name}进行了更改,邮箱地址:{user.user_account},本次花费了{_mysql.GetLastExecutionTime()}毫秒");
                _mysql.Close();
                return count;
            }
            else
            {
                _logger.Error($"更改用户出现错误,错误的sql语句:{_mysql.GetLastExecutedSql()},错误的信息:{_mysql.GetLastError()}");
                _mysql.Close();
                return -1;
            }
        }
        // 功能:注册成功后将用户的信息存储到redis中
        // 参数:一个User类型代表用户的信息
        // 返回:空的返回
        private void StoreUserInfoInRedis(User user)
        {
            // 生成一个唯一的会话ID
            string sessionId = Guid.NewGuid().ToString();

            // 获取 Redis 数据库实例
            IDatabase db = _redis.GetDatabase();
            string userInfoJson = JsonSerializer.Serialize(user);
            db.StringSet(sessionId, userInfoJson);                            // 序列化的User信息存入到redis中
            db.KeyExpire(sessionId, TimeSpan.FromMinutes(30));  // redis的过期时间

            // 设置 Cookie 的选项
            CookieOptions options = new CookieOptions();
            options.Expires = DateTime.Now.AddMinutes(30);
            options.HttpOnly = true;

            // 将 sessionId 传回以用于客户端的cookie中
            _httpContextAccessor.HttpContext.Response.Cookies.Append("SessionId", sessionId, options);
        }

        // 功能:从远程的redis中获取用户的信息
        // 参数:一个HttpContext里面存放了redis的key
        // 返回:查询成功返回一个用户信息,失败返回null
        public User GetUserInfoFromRedis(HttpContext httpContext)
        {
            // 从客户端的 Cookies 中获取 sessionId
            string sessionId;
            if ( httpContext.Request.Cookies.TryGetValue("SessionId",out sessionId))
            {
                if (sessionId.IsNullOrEmpty())
                {
                    return null;
                }

                // 获取 Redis 数据库实例
                IDatabase db = _redis.GetDatabase();

                // 使用 sessionId 从 Redis 中获取用户信息
                string userInfoJson = db.StringGet(sessionId);

                if (!string.IsNullOrEmpty(userInfoJson))
                {
                    // 将 JSON 数据反序列化为 User 对象并返回
                    return JsonSerializer.Deserialize<User>(userInfoJson);
                }
            }

            // 如果没有找到有效的 sessionId 或用户信息，返回 null
            return null;
        }

        // 功能:检验用户是否登录和是否具有操作这个页面的权限
        // 参数:一个HttpContext用于获取客户端的cooke,一个权限字符串用于指定要检查的权限等级
        // 返回:这是一个枚举值定义在UserStatus中，如果通过返回Authorized,如果没登录返回NotLoggedIn,如果没有权限NoPermission
        public UserStatus CheckUserPermissionSync(HttpContext context, string requiredPermission)
        {
            // 从cookie中获取sessionId
            var sessionId = context.Request.Cookies["SessionId"];

            if (string.IsNullOrEmpty(sessionId))
            {
                // 如果没有sessionId，那么用户还没有登录
                return UserStatus.NotLoggedIn;
            }

            // 获取一个IDatabase对象
            var db = _redis.GetDatabase();

            // 使用sessionId从Redis中获取用户的数据
            var userDataJson = db.StringGet(sessionId);

            if (userDataJson.IsNullOrEmpty)
            {
                // 如果没有获取到数据，那么用户还没有登录或者他们的登录状态已经过期
                return UserStatus.NotLoggedIn;
            }

            db.KeyExpire(sessionId, TimeSpan.FromMinutes(30));  // 刷新,redis的过期时间
            CookieOptions options = new CookieOptions();       
            options.Expires = DateTime.Now.AddMinutes(30);
            options.HttpOnly = true;
            context.Response.Cookies.Append("SessionId", sessionId, options); // 刷新cookies的过期时间

            // 将用户数据从JSON字符串反序列化为User对象
            var user = JsonSerializer.Deserialize<User>(userDataJson);

            // 在这里,检查用户是否具有执行当前操作的权限
        
            // 如果用户已经登录并且具有所需的权限，返回Authorized
            return UserStatus.Authorized;
        }

        // 功能:根据一个用户的账号删除一个用户
        // 参数:传入一个User里面包含了要擅长用户的账号
        // 返回:执行成分返回数据库影响的条数1,失败返回-1
        public int DelUserServer(User user)
        {
            _mysql.Open();
            string query = "DELETE FROM T_USER WHERE user_account=@user_account";
            Dictionary<string, object> parameters = new Dictionary<string, object>
            {
                {"@user_account",user.user_account }
            };
           int count=_mysql.ExecuteNonQuery(query, parameters);
            if(count > 0)
            {
                _logger.Info($"删除了一个新用户:{user.user_name},用户ID:{user.user_id},本次花费了{_mysql.GetLastExecutionTime()}毫秒");
                _mysql.Close();
                return count;
            }
            else
            {
                _logger.Error($"删除用户出现错误,错误的sql语句:{_mysql.GetLastExecutedSql()},错误的信息:{_mysql.GetLastError()}");
                _mysql.Close();
                return -1;
            }
        }

         // 功能：用于查询数据库里的所有用户并展示在前端页面
         // 参数:不需要任何参数
         // 返回:查询成功返回一个List<User>包含了所有的用户信息，查询失败返回null
        public List<User> SltServer()
        {
            _mysql.Open();

            string query = "SELECT * FROM T_USER";

            DataSet data = _mysql.ExecuteQuery(query);
            if (data == null || data.Tables[0].Rows.Count == 0)
            {
                _mysql.Close();
                // 查询出先错误
                _logger.Error($"查询出错,错误的sql语句:{_mysql.GetLastExecutedSql()},错误的信息:{_mysql.GetLastError()}");
                return null;
            }
            else
            {
                List<User> resultList = new List<User>();

                foreach (DataRow row in data.Tables[0].Rows)
                {
                    User newUser = new User();

                    newUser.user_name = row["user_name"].ToString();
                    newUser.user_account = row["user_account"].ToString();
                    newUser.phone = row["phone"].ToString();
                    newUser.role_id = row["role_id"].ToString();

                    resultList.Add(newUser);
                }
                _mysql.Close();
                return resultList;
            }
        }

        //功能：用于查询出需要修改的用户信息单独展示在一个页面
        //参数：传入一个user里面包含了修改课程的名称
        //返回:执行成分返回数据库影响的条数1,失败返回-1
        public User SltUpdServer(User user)
        {
            _mysql.Open();
            string query = "SELECT * FROM T_USER WHERE user_account=@user_account";
            Dictionary<string, object> parameters = new Dictionary<string, object>
            {
                {"@user_account",user.user_account !}
            };
            DataSet data=_mysql.ExecuteQuery(query,parameters);
               if (data == null || data.Tables[0].Rows.Count == 0)
            {
                _mysql.Close();
                // 查询出先错误
                _logger.Error($"查询出错,错误的sql语句:{_mysql.GetLastExecutedSql()},错误的信息:{_mysql.GetLastError()}");
                return null;
            }
            else
            {
                User user1 = new User();

                foreach (DataRow row in data.Tables[0].Rows)
                {
                    user1.user_name = row["user_name"].ToString();
                    user1.user_account = row["user_account"].ToString();
                    user1.phone = row["phone"].ToString();
                    user1.role_id = row["role_id"].ToString();

                   
                    break;
                }
                _mysql.Close();
                return user1;
            }

        }

        //功能：根据用户姓名查询出用户信息
        //参数：传入一个user里面包含了修改课程的名称
        //返回:执行成分返回数据库影响的条数1,失败返回-1
        public List<User> Slt2Server(User user)
        {
            _mysql.Open();
            string query = "SELECT * FROM T_USER WHERE user_name LIKE @user_name";
            Dictionary<string, object> parameters = new Dictionary<string, object>
    {
        {"@user_name", "%" + user.user_name + "%" }
    };
            DataSet data = _mysql.ExecuteQuery(query, parameters);
            _mysql.Close();

            if (data == null || data.Tables[0].Rows.Count == 0)
            {
                // 查询出现错误
                _logger.Error($"查询出错，错误的SQL语句：{_mysql.GetLastExecutedSql()}，错误的信息：{_mysql.GetLastError()}");
                return null;
            }

            List<User> resultList = new List<User>();

            foreach (DataRow row in data.Tables[0].Rows)
            {
                User newUser = new User();

                newUser.user_name = row["user_name"].ToString();
                newUser.user_account = row["user_account"].ToString();
                newUser.phone = row["phone"].ToString();
                newUser.role_id = row["role_id"].ToString();

                resultList.Add(newUser);
            }

            return resultList;
        }

        public List<string> GetNowPower(HttpContext context)
           {
            List<string>result= new List<string>();
            // 从cookie中获取sessionId
            var sessionId = context.Request.Cookies["SessionId"];

            if (string.IsNullOrEmpty(sessionId))
            {
                // 如果没有sessionId，那么用户还没有登录
                return result; 
            }

            // 获取一个IDatabase对象
            var db = _redis.GetDatabase();

            // 使用sessionId从Redis中获取用户的数据
            var userDataJson = db.StringGet(sessionId);

            if (userDataJson.IsNullOrEmpty)
            {
                // 如果没有获取到数据，那么用户还没有登录或者他们的登录状态已经过期
                return result;
            }

            db.KeyExpire(sessionId, TimeSpan.FromMinutes(30));  // 刷新,redis的过期时间
            CookieOptions options = new CookieOptions();
            options.Expires = DateTime.Now.AddMinutes(30);
            options.HttpOnly = true;
            context.Response.Cookies.Append("SessionId", sessionId, options); // 刷新cookies的过期时间

            // 将用户数据从JSON字符串反序列化为User对象
            var user = JsonSerializer.Deserialize<User>(userDataJson);

            // 在这里,检查用户是否具有执行当前操作的权限
            result = GetPower(user.role_id);

            // 如果用户已经登录并且具有所需的权限，返回Authorized
            return result;
        }

        public List<string> GetPower(string role_id)
        {
            _mysql.Open();

            string query = "SELECT * FROM T_ROLE_PERMISSION \r\nLEFT JOIN T_PERMISSION on " +
                "T_ROLE_PERMISSION.permission_id=T_PERMISSION.permission_id\r\nWHERE role_id=@role_id";

            Dictionary<string, object> parameters = new Dictionary<string, object>
            {
                {"@role_id",role_id },
            };

            DataSet data = _mysql.ExecuteQuery(query, parameters);
            if (data == null || data.Tables[0].Rows.Count == 0)
            {
                _mysql.Close();
                // 查询出先错误
                _logger.Error($"查询出错,错误的sql语句:{_mysql.GetLastExecutedSql()},错误的信息:{_mysql.GetLastError()}");
                return null;
            }
            else
            {
                List<string> res = new List<string>();

                foreach (DataRow row in data.Tables[0].Rows)
                {
                    res.Add(row["permission_name"].ToString());
                }
                _mysql.Close();

                return res;
            }
        }

    }
}
